﻿using System;
using System.Collections.Generic;
using System.Text;

namespace daStaticAnalyser.Analysers
{
    using daBase.Analyser;
    using daSyntaxAnalyser.SyntaxTree;
    using daStaticAnalyser.Analysers;
    using daBase.Objects;
    using daStaticAnalyser;
    [AnalyserDefaultSettings("Цикломатическая сложность.", "test", 0, "test")]
    public class CyclomaticAnalyser : BaseStaticAnalyser
    {
       
        /// <summary>
        /// Расчет цикломатической сложности оператора
        /// </summary>
        /// <param name="Element">узел, соответствующий </param>
        /// <returns>цикломатическая </returns>
        private int CalculateCyclomatic(ISyntaxTreeElement Element)
        {
            if (Element == null)
                return 0;
            int result = 0;
            if ((Element is CaseBlockStatementElement) ||
                (Element is TryStatementElement) ||
                (Element is RepeatStatementElement) ||
                (Element is ExceptOnStatementElement) ||
                (Element is ForStatementElement) ||
                (Element is TestStatementElement) ||
                (Element is WhileStatementElement))
                result = 1;
            foreach (ISyntaxTreeElement element in Element)
                result += CalculateCyclomatic(element);
            return result;
        }

        /// <summary>
        /// Расчет цикломатической сложности метода
        /// </summary>
        /// <param name="Body">узел, соответствующий телу метода</param>
        /// <returns>цикломатическая сложность</returns>
        private int CalculateCyclomatic(MethodBodyElement Body)
        {
            if (Body != null)
                return CalculateCyclomatic(Body.Statement) + 1;
            return 0;
        }
        // расчитанная цикломатическая сложность
        private int diff;

        protected override void DoAnalyse(SyntaxTreeArgs es)
        {
            String MethodName = "";
            if (CheckMethod_GetName(es, out MethodName))
            {
                OuterMethodElement Method = es.Element as OuterMethodElement;

                diff = CalculateCyclomatic(Method.Body);
                AddMetric("Метрика МакКейба(Упрощённая)", diff,
                    MethodName, 
                    Method.StartInfo.File,
                    Method.StartInfo.Line);

                ControlGraph CG = new ControlGraph();
                CG.Build(Method.Body.Statement);
                int e = CG.Links.Count;//Количество дуг
                int n = CG.Elements.Count;//Количество вершин
                int p = 1;//Число компонент связности
                int Z = e - n + 2 * p;

                AddMetric("Метрика МакКейба", Z,
                    MethodName,
                    Method.StartInfo.File,
                    Method.StartInfo.Line);
            }
        }
    }
}
